﻿//////////////////////////////////////////////////////////////////
//
// UtilitiesPriorityQueue.cs
//
// Copyright (c) 2012 Dan Pike.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation files
// (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Utilities;

namespace TestCharles
{
   [TestClass]
   public class UtilitiesPriorityQueue
   {
      private class Thing
      {
         public Thing(int value)
         {
            Value = value;
         }
         public int Value;
      }

      [TestMethod]
      public void AddRemoveOne()
      {
         PriorityQueue<Thing, int> queue = new PriorityQueue<Thing, int>((a, b) => Math.Sign(a - b));

         Thing thing123 = new Thing(123);
         queue.SetPriority(thing123, 100);
         Assert.AreEqual(1, queue.Count);
         Assert.AreEqual(100, queue.PeekNextPriority());
         Thing extracted123 = queue.RemoveNext();
         Assert.AreEqual(0, queue.Count);
         Assert.AreEqual(123, extracted123.Value);
      }

      [TestMethod]
      public void AddTwoInSequence()
      {
         PriorityQueue<Thing, int> queue = new PriorityQueue<Thing, int>((a, b) => Math.Sign(a - b));

         Thing thing123 = new Thing(123);
         Thing thing456 = new Thing(456);
         queue.SetPriority(thing123, 77);
         queue.SetPriority(thing456, 78);
         Assert.AreEqual(2, queue.Count);
         Assert.AreEqual(77, queue.PeekNextPriority());
         Thing extracted123 = queue.RemoveNext();
         Assert.AreEqual(1, queue.Count);
         Assert.AreEqual(123, extracted123.Value);
         Assert.AreEqual(78, queue.PeekNextPriority());
         Thing extracted456 = queue.RemoveNext();
         Assert.AreEqual(0, queue.Count);
         Assert.AreEqual(456, extracted456.Value);
      }

      [TestMethod]
      public void TwoSamePriority()
      {
         PriorityQueue<Thing, int> queue = new PriorityQueue<Thing, int>((a, b) => Math.Sign(a - b));

         Thing thing1 = new Thing(123);
         queue.SetPriority(thing1, 77);
         Assert.AreEqual(1, queue.Count);
         Assert.AreEqual(77, queue.PeekNextPriority());

         Thing thing2 = new Thing(456);
         queue.SetPriority(thing2, 77);
         Assert.AreEqual(2, queue.Count);
         Assert.AreEqual(77, queue.PeekNextPriority());

         Thing thingA = queue.RemoveNext();
         Assert.AreEqual(1, queue.Count);
         Assert.AreEqual(77, queue.PeekNextPriority());

         Thing thingB = queue.RemoveNext();
         Assert.AreEqual(0, queue.Count);

         // Not defined which one comes out first but they must both
         // come out of the queue, so check it's one or the other
         // sequence
         Assert.AreNotSame(thingA, thingB);
         Assert.AreNotEqual(thingA, thingB);
         if (123 == thingA.Value)
         {
            Assert.AreEqual(456, thingB.Value);
         }
         else
         {
            Assert.AreEqual(456, thingA.Value);
            Assert.AreEqual(123, thingB.Value);
         }
      }

      [TestMethod]
      public void ChangeSequence()
      {
         PriorityQueue<Thing, int> queue = new PriorityQueue<Thing, int>((a, b) => Math.Sign(a - b));

         // Set up queue
         Thing thing123 = new Thing(123);
         Thing thing456 = new Thing(456);
         queue.SetPriority(thing123, 77);
         queue.SetPriority(thing456, 78);
         
         // Change the order
         queue.SetPriority(thing123, 79);
         Assert.AreEqual(2, queue.Count);

         // Check that the order has swapped
         Assert.AreEqual(78, queue.PeekNextPriority());
         Thing extracted456 = queue.RemoveNext();
         Assert.AreEqual(1, queue.Count);
         Assert.AreEqual(456, extracted456.Value);

         Assert.AreEqual(79, queue.PeekNextPriority());
         Thing extracted123 = queue.RemoveNext();
         Assert.AreEqual(0, queue.Count);
         Assert.AreEqual(123, extracted123.Value);
      }
   }
}
